package com.jonny.dbtools.service.impl

import cn.smallbun.screw.core.Configuration
import cn.smallbun.screw.core.engine.EngineConfig
import cn.smallbun.screw.core.engine.EngineTemplateType
import cn.smallbun.screw.core.execute.DocumentationExecute
import cn.smallbun.screw.core.process.ProcessConfig
import cn.smallbun.screw.core.util.StringUtils
import com.jonny.dbtools.components.Alert
import com.jonny.dbtools.constant.DBType
import com.jonny.dbtools.constant.Doc
import com.jonny.dbtools.constant.Type
import com.jonny.dbtools.constant.Urls
import com.jonny.dbtools.domain.DatabaseDTO
import com.jonny.dbtools.service.DbService
import com.jonny.dbtools.utils.ValidatorUtil
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import org.slf4j.Logger
import org.slf4j.LoggerFactory

import javax.sql.DataSource
import java.text.MessageFormat

class DbServiceImpl implements DbService {

    private Logger LOG = LoggerFactory.getLogger(DbServiceImpl.class)

    DbServiceImpl() {}

    @Override
    public void export(DatabaseDTO databaseDTO) {

        def map = ValidatorUtil.valid(databaseDTO);
        if (map.get("flag") as boolean) {
            Alert.warn(map.get("msg"))
            return
        }

        if (DBType.POSTGRES.equals(databaseDTO.dbTpe)) {
            if (StringUtils.isBlank(databaseDTO.getSchema())) {
                Alert.warn("模式(schema)不能为空")
                return
            }
            //pg < 9.4: searchpath=xxx   > 9.3 currentSchema=xxx
            databaseDTO.setDbName(String.format("%s?currentSchema=%s", databaseDTO.getDbName(), databaseDTO.getSchema()))
        }

        exe(databaseDTO);
        LOG.info("export successful!");
    }

    private void exe(DatabaseDTO databaseDTO) {

        String path = System.getProperty("user.home")

        // 生成文件配置
        EngineConfig engineConfig = EngineConfig.builder()
        // 生成文件路径，自己mac本地的地址，这里需要自己更换下路径
                .fileOutputDir(path)
                .fileName(String.format("%s数据库表设计", databaseDTO.getDbTpe()))
                .openOutputDir(true)
                .fileType(Doc.DOCS.get(databaseDTO.getDocType()))
                .produceType(EngineTemplateType.freemarker).build();

        // 生成文档配置（包含以下自定义版本号、描述等配置连接）
        Configuration config = Configuration.builder()
                .version("1.0.3")
                .description(String.format("%s数据库表设计", databaseDTO.getDbTpe()))
                .dataSource(dataSource(databaseDTO))
                .engineConfig(engineConfig)
                .produceConfig(getProcessConfig(databaseDTO))
                .build();

        // 执行生成
        new DocumentationExecute(config).execute();
    }

    /**
     * 配置想要生成的表+ 配置想要忽略的表
     * @return 生成表配置
     */
    static ProcessConfig getProcessConfig(DatabaseDTO databaseDTO) {

        // 忽略表名
        List<String> ignoreTableName = databaseDTO.getIgnoreTableName()?.split(",")?.findAll { it } as List

        // 忽略表前缀，如忽略a开头的数据库表
        List<String> ignorePrefix = databaseDTO.getIgnorePrefix()?.split(",")?.findAll { it  } as List

        // 忽略表后缀
        List<String> ignoreSuffix = databaseDTO.getIgnoreSuffix()?.split(",")?.findAll { it } as List

        return ProcessConfig.builder()
                .designatedTableName(new ArrayList<>())//根据名称指定表生成
                .designatedTablePrefix(new ArrayList<>())//根据表前缀生成
                .designatedTableSuffix(new ArrayList<>())//根据表后缀生成
                .ignoreTableName(ignoreTableName)//忽略表名
                .ignoreTablePrefix(ignorePrefix)//忽略表前缀
                .ignoreTableSuffix(ignoreSuffix)//忽略表后缀
                .build();
    }

    private static DataSource dataSource(DatabaseDTO databaseDTO) {


        Properties prop = new Properties()
        prop.setProperty("driverClassName", Type.DRIVERS.get(databaseDTO.getDbTpe()))
        prop.setProperty("username", databaseDTO.getUsername())
        prop.setProperty("password", databaseDTO.getPassword())
        prop.setProperty("jdbcUrl", MessageFormat.format(Urls.URLS.get(databaseDTO.getDbTpe()), databaseDTO.getHost(), String.valueOf(databaseDTO.getPort()), databaseDTO.getDbName()))

        HikariConfig config = new HikariConfig(prop)
        return new HikariDataSource(config)
    }
}